home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / docs / mags / saku18.lha / Teksti / Ohjelmointi.txt < prev    next >
Text File  |  1996-04-28  |  18KB  |  407 lines

  1. 2
  2. 1*
  3. {A              Järjestelmäohjelmoinnin alkeiskurssi - Osa 5: DOS
  4. {A              -------------------------------------------------
  5.  
  6. {8                                  Sami  Klemola
  7.  
  8.   
  9. Tällä kertaa teemme läpileikkauksen dos.libraryyn. Ensin kuitenkin pieni korjaus
  10. kurssin edellisen osan tekstiin. Virhe ei ollut minun - tietenkään - minähän  en
  11. tunnetusti tee virheitä. Kyse on siitä, että  puhuin  olioperustaisista  kirjas-
  12. toista, ja oikolukija muutti sen oliopohjaiseksi tietämättä, että ne ovat  kaksi
  13. aivan eri asiaa, ja teki näin tekstiin asiavirheen. Oliopohjainen  on  sellainen
  14. systeemi, joka toimii oliomuotoisesti vain tietyiltä  osilta,  kun  taas  Triton
  15. toimii kokonaan olioiden voimalla eli se on olioperustainen.  Pahoittelen  sitä,
  16. että oikolukija kajosi taas asiaan, johon hänen ei olisi pitänyt puuttua.  Tästä
  17. kuitenkin nyt asiaan. 
  18.  
  19.  
  20. {DDOS
  21.  
  22. Kun Amiga käynnistyy, käynnistyslevyltä ladataan koodi, joka alustaa  dos.libra-
  23. ryn. Se jatkaa prosessia  muodostamalla  tiedostojärjestelmät  ja  suorittamalla
  24. startup-sequencen. DOS on keskeinen osa kaikkea muutakin toimintaa, joten on  jo
  25. aika, että tutustumme siihen. DOS tarjoaa  ohjelmoijalle  funktiot  tiedostojen,
  26. hakemistojen ja prosessien käsittelyyn sekä moneen muuhun hommaan. Tässä  osassa
  27. selvitän  yksinkertaisimpien  toimintojen  käyttämisen.  Aloitamme   tiedostojen
  28. käsittelystä, mutta sitä ennen hieman teoriaa.
  29.  
  30. Massamuistitoiminnot ovat kolmitasoiset. Alimmalla tasolla  ovat  ajurit,  jotka
  31. ohjaavat yksittäisiä tietokoneeseen liitettyjä laitteita. Seuraavalla tasolla on
  32. tiedostojärjestelmä, joka komentaa laiteajureita. Ylimmällä tasolla on DOS, joka
  33. ohjaa tiedostojärjestelmien toimintaa. Ohjelmoija voi käyttää tätä  hierarkkista
  34. rakennelmaa helposti puhumalla DOSille. Kaikki alemman tason operaatiot  sujuvat
  35. automaattisesti ilman, että ohjelmoijan tarvitsee tietää niistä  mitään.  Hieman
  36. tarkemmin näistä asioista tarinoin PFS- ja DSP-artikkeleissani numerossa 11.
  37.  
  38. Ohjelmoija käyttää tiedostoja funktioiden Open(), Close(), Read() jne.  välityk-
  39. sellä. Osa funktioista on puskuroituja, minkä ansiosta toiminta on erittäin  no-
  40. peaa, vaikka ohjelma lukisi esimerkiksi vain muutaman tavun  kerrallaan.  Toinen
  41. mahdollisuus on käyttää C-kielen vakiofunktioita,  esim.  fopen(),  fread()  tai
  42. open(), read() jne. Minä suosin DOS-funktioiden kutsumista,  mutta  jälkimmäistä
  43. vaihtoehtoa kannattaa harkita, jos on mahdollisuus, että ohjelma voidaan portata
  44. toiseen käyttöjärjestelmään. Tällöin on syytä käyttää niin  vähän  käyttöjärjes-
  45. telmäkohtaisia funktioita kuin mahdollista. 
  46.  
  47.  
  48. {DTiedostojen käsittely
  49.  
  50. Tiedosto avataan funktiolla Open(). Sille annetaan osoitin tiedoston  nimeen  ja
  51. moodi, joka on MODE_OLDFILE, jos tiedosto  avataan  lukemista  varten,  tai  MO-
  52. DE_NEWFILE, jos tiedosto tulee luoda. On olemassa  vielä  kolmaskin  moodi,  MO-
  53. DE_READWRITE, joka avaa tiedoston lukemista varten, mutta luo sen, jos  sitä  ei
  54. ole olemassa. Kirjoittamista varten avattua tiedostoa (MODE_NEWFILE) ei voi ava-
  55. ta toistamiseen, mutta MODE_READWRITE:llä avatun voi. Open() palauttaa  osoitti-
  56. men tiedoston kahvaan eli struktuuriin, joka sisältää tietoja siitä. Osoitin  on
  57. BCPL-kielinen eli longword-osoitin, joten sitä pitää siirtää kaksi bittiä vasem-
  58. malle, että siitä saa CPU-kelpoisen. Sitä ei kuitenkaan normaalisti tarvitse it-
  59. se  käyttää,  vaan  se  annetaan  muille  funktioille,   esim.   Read(),   niitä
  60. käytettäessä.
  61.  
  62.  
  63. Tiedosto suljetaan funktiolla Close(). Sille  annetaan  Open()-funktiolta  saatu
  64. kahva. Tässä on pieni esimerkkikoodi tiedoston avaamisesta ja sulkemisesta: 
  65.  
  66. {BBPTR file; /* Kahva */
  67.  
  68. {B    if( file = Open( "T:Tiedosto", MODE_OLDFILE )) {
  69.  
  70.         ... tiedoston käyttöä ...
  71.  
  72. {B        Close(file);
  73. {B    } else printf("virhe: eipä ollut tiedostoa\n");
  74.  
  75. Tästä kehittelemällä voidaan helposti kirjoittaa funktio, joka kertoo, onko
  76. haluttu tiedosto olemassa:
  77.  
  78. {BBOOL exists( STRPTR name ) {
  79. {BBPTR file;
  80. {B    if( file = Open( name, MODE_OLDFILE )) Close(file);
  81. {B    return file ? TRUE: FALSE;
  82. {B};
  83.  
  84. Funktion käyttäminen on helppoa ja samantapaista kuin Rexxissä:
  85.  
  86. {B    if( exists( "s:CopyStuff" )) {
  87.  
  88.         ... suorita CopyStuff-skripti ...
  89.  
  90. {B    }
  91.  
  92.  
  93. Tämä esimerkki katsoo, onko SYS:S -hakemistossa  CopyStuff-nimistä  skriptiä  ja
  94. jos on, suorittaisi sen. Komentojen  (ja  skriptien)  suorittaminen  käsitellään
  95. vielä tässä osassa.
  96.  
  97. DOSissa on kätevä funktio AddPart(), jonka avulla voidaan liittää toisiinsa  ha-
  98. kemistonimiä ja tiedostonimiä. Hakemiston nimihän voi päättyä  kaksoispisteeseen
  99. tai kauttaviivaan, tai siinä ei välttämättä ole mitään erityistä merkkiä  lopus-
  100. sa. Näin ollen hakemistopolun muodostaminen merkkijonoja  kopioimalla  on  huono
  101. idea. AddPart() osaa käsitellä kaikenlaiset nimet oikein, ja sen avulla on help-
  102. poa yhdistää hakemiston ja tiedoston nimet. Oletetaan, että meillä  on  puskuri,
  103. jossa on valmiina hakemiston nimi ja siihen pitää liittää  tiedostonimi.  Se  on
  104. helppoa: 
  105.  
  106. {Bchar buf[100] = "DEVS:Monitors";
  107.  
  108. {B    AddPart( buf, "Super72", 100 );
  109.  
  110. Kutsun jälkeen puskurissa lukee "DEVS:Monitors/Super72". AddPart():lle  annetaan
  111. viimeisenä argumenttina käytettävissä olevan tilan suuruus eli puskurin  pituus.
  112. On olemassa toinenkin funktio, FilePart(). Se palauttaa osoittimen hakemistopol-
  113. kumerkkijonon viimeiseen elementtiin, joka on tiedostonimi  tai  hakemisto,  jos
  114. polussa ei ole tiedostonimeä. Edellisen jälkeen kutsu "FilePart( buf )"  palaut-
  115. taisi siis osoittimen puskuriin kohtaan, jossa on "Super72".
  116.  
  117. Tiedostoon liittyy osoitin, joka määrää, mihin  kohtaan  tiedostoon  kohdistetut
  118. toiminnot osuvat. Kun tiedosto avataan, osoitin osoittaa tiedoston  alkuun.  Kun
  119. tiedostosta luetaan dataa, osoitin siirtyy eteenpäin niin paljon kuin on luettu.
  120. Jos luetaan sata tavua, osoitin osoittaa tiedostossa  kohtaan  100.  Ensimmäinen
  121. kohta on 0 ja suurin yhtä pienempi kuin tiedoston pituus. Kohtaa voidaan muuttaa
  122. kutsumalla funktiota Seek(). Se etsii tiedostosta tietyn kohdan, ja  tiedostosta
  123. voidaan lukea halutusta kohdasta. Katso seuraavaa esimerkkiä, niin  näet,  miten
  124. Seek()-funktiota käytetään.
  125.  
  126. Tiedostosta luetaan funktiolla Read(). Sille annetaan niin ikään tiedoston kahva
  127. ja sitten osoitin muistialueeseen, johon luettu data sijoitetaan,  sekä  luetta-
  128. vien tavujen määrä. Tiedostoon kirjoitetaan aivan samalla tavalla, mutta funktio
  129. on Write(). Katsotaanpa: 
  130.  
  131. {BBPTR file;          /* Kahva */
  132. {BUBYTE space[100];   /* Muistialue */
  133.  
  134. {B    if( file = Open( "Data", MODE_OLDFILE )) {
  135.  
  136.         /* Read() palauttaa luettujen tavujen lukumäärän. */
  137.  
  138. {B        if( Read( file, space, 100 ) < 100 ))
  139. {B            printf("Jotain vikaa. Ei saatu sataa tavua.\n");
  140.  
  141.         /* Haetaan tiedostosta kohta, joka on 300 tavua alusta. */
  142.  
  143. {B        Seek( file, OFFSET_BEGINNING, 300 );
  144.  
  145.         /* Kirjoitetaan sinne. Myös Write() palauttaa tavumäärän. */
  146.  
  147. {B        if( Write( file, space, 50 ) < 50 ))
  148.  
  149.             /* Ei onnistunut. Nyt käytämme hieman kehittyneempää
  150.                tekniikkaa. Kysymme DOSilta virhekoodin ja näytämme
  151.                käyttäjälle virheilmoituksen. Se saattaa näyttää vaikka
  152.                tältä: "error: disk full". */
  153.  
  154. {B            PrintFault(IoErr(),"error");
  155.  
  156. {B        Close(file);
  157. {B    } else printf("Ei dataa.\n");
  158.  
  159. Vielä takaisin Seek()-funktioon. Sille annetaan kahva, moodi ja lukema. Moodille
  160. on kolme vaihtoehtoa. Jos se on kuten esimerkissä eli  OFFSET_BEGINNING,  lukema
  161. on suoraan uusi osoitin tiedostossa. Moodi voi olla myös OFFSET_CURRENT, jolloin
  162. lukema lisätään nykyiseen osoittimeen. Lukema voi olla myös  negatiivinen,  jol-
  163. loin paikka siirtyy taaksepäin. Viimeinen vaihtoehto on OFFSET_END, joka on tie-
  164. doston loppu. Tällöin moodin on pakko olla negatiivinen tai nolla, koska tiedos-
  165. ton lopun ohi ei voi mennä. Seek()-funktion avulla voi tätä moodia käyttäen sel-
  166. vittää tiedoston pituuden: 
  167.  
  168. {BULONG FileLength(BPTR file) {
  169. {BULONG currpos;
  170. {B    currpos = Seek( file, OFFSET_END, 0 );
  171. {B    return Seek( file, OFFSET_BEGINNING, currpos );
  172. {B};
  173.  
  174. Tämä funktio palauttaa tiedoston pituuden. Seek() toisin kuin vakio-C:n  lseek()
  175. palauttaa osoittimen arvon ENNEN muutosta. Siksi tarvitaan kaksi  kutsua.  Vasta
  176. jälkimmäinen palauttaa edellisen kutsun asettaman paikan  eli  tiedoston  lopun.
  177. Samalla se asettaa edellisen kutsun palauttaman arvon eli edeltäneen paikan  ta-
  178. kaisin voimaan. 
  179.  
  180.  
  181.  
  182.  
  183. {9Puskuroidut funktiot
  184.  
  185. Read() ja Write() eivät ole DOSin puolella puskuroituja funktioita. Pieniä luku-
  186. ja ja kirjoituksia tehtäessä kannattaa käyttää funktioita FGetC() ja FPutC(). Ne
  187. vastaavat vakiofunktioita fgetc() ja fputc() eli niillä voit lukea tai  kirjoit-
  188. taa yhden merkin. FGetC():lle annetaan  argumenttina  vain  tiedoston  kahva  ja
  189. FPutC():lle lisäksi kirjoitettava merkki.
  190.  
  191. Lisäksi DOSissa on string-versiot eli FGets() ja FPuts(). Ne  vastaavat  vastaa-
  192. vasti standardeja fgets()- ja fputs()-funktioita. Merkkijono  kirjoitetaan  tie-
  193. dostoon kutsulla "FPuts( file, "Merkkijono"  );".  FGets()  toimii  vastaavasti,
  194. mutta argumetit ovat samat kuin Read():lla. Puskurin lisäksi annetaan siis  pus-
  195. kurin pituus, ja saat puskuriin joko dataa LF-merkkiin asti tai niin paljon kuin
  196. siihen mahtuu. 
  197.  
  198. {9Muut operaatiot
  199.  
  200. Tiedostoille voidaan tehdä vähän muutakin. Kuten äsken kerroin, osa  DOSin  tie-
  201. dostofunktioista on puskuroituja ja osa ei,  joten  ongelmia  voi  seurata,  jos
  202. niitä käytetään peräkkäin samaan tiedostoon. Puskuroimaton kirjoitus puskuroidun
  203. kirjoituksen jälkeen voi tapahtua ensin! Puskuroimaton kirjoitus ei  välttämättä
  204. aikaansaa välittömästi levyoperaatioita. Data voidaan kirjoittaa puskuriin odot-
  205. tamaan kirjoittamista levylle. Jos haluat pakottaa kirjoittamisen levylle,  voit
  206. kutsua funktiota Flush(), niin se tehdään välittömästi: 
  207.  
  208. {B    Flush( file );
  209.  
  210. Tämä on pakollista, kun on esimerkiksi ensin käytetty FPutC()- tai FPuts()-funk-
  211. tiota ja sitten halutaan tehdä Write()-kutsu. DOSissa on myös funktiot tiedosto-
  212. jen tuhoamiselle ja siirtämiselle. Tiedostoa ei avata ennen näitä  operaatioita,
  213. vaan niille annetaan nimiä merkkijonoina. Tiedosto tuhotaan näin: 
  214.  
  215. {B    DeleteFile( "T:Temppifile" );
  216.  
  217. Nimenmuutos on yhtä helppoa kuin shellissä:
  218.  
  219. {B    Rename( "T:CurrentStore", "T:OldStore" );
  220.  
  221. Tämä muuttaa nykyisen tallennustiedoston vanhaksi  tiedostoksi.  Sekä  tuhottava
  222. että uudelleennimettävä kohde voi olla  myös  hakemisto.  Tuhottavan  hakemiston
  223. pitää olla tyhjä. Mikäli uudelleennimeämisen lähde on tiedosto ja kohde hakemis-
  224. to, tiedosto siirretään hakemistoon. Jos kohdehakemisto on olemassa ja  lähdekin
  225. on hakemisto, on seurauksena virhe. Tiedostoa tai hakemistoa ei voi siirtää toi-
  226. selle levylle. Toiminta on siis melko lailla sama kuin  shellissä  Rename-komen-
  227. non. 
  228.  
  229.  
  230. {DInteraktiiviset tiedostot
  231.  
  232. CON-handlerin avulla voit avata tiedoston, joka onkin ikkuna! Tiedostoon kirjoi-
  233. tettu data tulostuu siihen ja siitä luettu data tulee  näppäimistöltä.  Tämä  on
  234. ehdottomasti kätevin tapa yksinkertaiseen kommunikaatioon käyttäjän kanssa. Kon-
  235. soli-ikkunaa käyttää mm. shell. Konsoli avataan  ihan  normaalisti  Open()-funk-
  236. tiolla ja suljetaan Close()-funktiolla. CON-handler huolehtii ikkunan avaamises-
  237. ta ja sulkemisesta. Voit kyllä toimittaa oman ikkunankin, mutta se on jo  hieman
  238. enemmän tarkkuutta vaativa toimenpide, joten siihen en tässä paneudu.
  239.  
  240. Open()-funktiolle annetaan samanlainen merkkijono kuin esimerkiksi  NewShell-ko-
  241. mennolle WINDOW-argumenttina. Konsoli siis on  mountattu  laitenimellä  CON,  ja
  242. sitä käytetään avaamisessa: 
  243.  
  244. {B    if( con = Open( "CON:0/0/640/256/MyWindow/CLOSE", MODE_OLDFILE )) {
  245.  
  246.  
  247. {B    } printf("Eipä auennut konsoli, ei.\n");
  248.  
  249. {6HUOM! Konsoli tulee aina avata MODE_OLDFILE:llä.
  250.  
  251. Laitenimen jälkeen tulevat ikkunan määritykset, ensin vasemman yläkulman koordi-
  252. naatit ja sen jälkeen ikkunan leveys ja korkeus sekä sen nimi ja optiot,  joista
  253. tässä annetaan CLOSE. Se tekee ikkunaan sulkunappulan. Optioilla voidaan  ikkuna
  254. avata esimerkiksi ilman reunoja tai tietylle ruudulle.  Merkkijono  sekä  kaikki
  255. käytettävissä olevat optiot on selitetty Using The System Software -kirjassa si-
  256. vuilla 7-38 - 7-40.
  257.  
  258. DOSissa on kaksi funktiota, joiden avulla voidaan ottaa  selvää,  onko  kyseessä
  259. tietyntyyppinen tiedosto. IsFilesystem() kertoo, onko tiedosto levyllä oleva oi-
  260. kea tiedosto palauttaen TRUE- tai  FALSE-statuksen.  Funktiolla  IsInteractive()
  261. voidaan selvittää, onko tiedosto interaktiivinen eli konsoli. Funktion  dokumen-
  262. taatiossa siitä käytetään hienosti termiä virtuaalinen  terminaali.  Kummallekin
  263. funktiolle annetaan parametrinä kahva tiedostoon.
  264.  
  265. Jokainen ohjelma saa käynnistyessään valmiina kaksi  interaktiivista  tiedostoa,
  266. stdin ja stdout. Niihin saa kahvan kutsumalla funktioita Input() ja Output(). Ne
  267. siis palauttavat kahvan  ohjelman  oletussyöte-  ja  tulostuskanaviin.  Funktiot
  268. eivät ota argumentteja. Interaktiiviseen tiedostoon eli konsoli-ikkunaan  tulos-
  269. tetaan kirjoittamalla tiedostoon:
  270.  
  271. {B    Write ( Output(), "Hei.\n", 5 );
  272.  
  273. Tämä funktiokutsu vastaa tulostusfunktiokutsua:
  274.  
  275. {B    printf("Hei\n" );
  276.  
  277. Tulostus siis menee tiedostoon, jonka kahvan Output()-funktio palautti, eli ole-
  278. tustulostuskanavaan, joka normaalisti on shell-ikkuna. Sitä  tarkoitusta  varten
  279. on myös oma funktio, PutStr(). Yllä olevaa vastaa yksinkertainen kutsu  "PutStr(
  280. "Hei.\n" );".
  281.  
  282. Tulostaminen konsoli-ikkunaan tällä tavalla on tietysti hieman  hankalaa,  joten
  283. kannattaa kirjoittaa funktio sitä varten: 
  284.  
  285. {BULONG Print(BPTR confile, STRPTR string) {
  286. {B    Write( confile, string, strlen(string) );
  287. {B};
  288.  
  289. Nyt tulostaminen konsoli-ikkunaan on helpompaa:
  290.  
  291. {B    Print( con, "Hei\n" );
  292.  
  293. Ongelmaksi tulee muotoiltujen merkkijonojen tulostaminen. Ratkaisu on  merkkijo-
  294. non formatointi kutsumalla RawDoFmt()-funktiota, mutta se  on  tehtävä  konekie-
  295. lellä. Toinen mahdollisuus on käyttää VFPrintf()-funktiota tulostamiseen.  Sille
  296. annetaan kahva, merkkijono ja argumenttitaulukko. Se  vastaa  toiminnaltaan  fp-
  297. rintf()-funktiota, mutta sen käyttäminen on erilaista. Argumentteja ei  työnnetä
  298. pinoon, vaan niistä muodostetaan edellä  mainittu  argumenttitaulukko.  Tämä  on
  299. tietysti hankalaa, joten kannattaa harkita konekielisen rutiinin kirjoittamista,
  300. joka toimisi välikappaleena.
  301.  
  302.  
  303.  
  304.  
  305. Minulla itselläni eivät ole ollenkaan käytössä kääntäjän tulostusfunktiot.  Olen
  306. kirjoittanut omat, jotka kutsuvat edelleen DOSin funktioita. Ne ovat  hyvin  yk-
  307. sinkertaiset - juuri sellaiset välikappaleet kuin äsken puhuin. Tässä on tarkoi-
  308. tukseen sopivan tulostusfunktion lähdekoodi: 
  309.  
  310. {B_cprintf          ; LONG cprintf(file,string[,arg][,arg][...])
  311.  
  312. {B         movem.l  d2-d3,-(sp)
  313. {B         move.l   12(sp),d1     /* Kahva */
  314. {B         move.l   16(sp),d2     /* Merkkijono */
  315. {B         lea      20(sp),a0     /* Argumentit */
  316. {B         move.l   a0,d3
  317. {B         Lib      VFPrintf,_DOSBase(a4)
  318. {B         movem.l  (sp)+,d2-d3
  319. {B         rts
  320.  
  321. Koodi tarvitsee near a4 -määrityksen, ja se kääntyy PhxAssilla. Tämä rutiini te-
  322. kee juuri sen, mistä puhuin, eli se  on  VFPrintf()-funktion  stub,  joka  antaa
  323. funktiolle osoittimen argumenttitaulukkoon. Huomaa, että osoite saadaan  lealla.
  324. C-kääntäjä siis luo argumenttitaulukon laittaessaan argumentit pinoon,  ja  tämä
  325. koodi antaa tulostusfunktiolle osoittimen pinoon siihen kohtaan, jossa  argumen-
  326. tit ovat. Kätevää, eikö totta? Nyt voimme tulostaa konsoli-ikkunaan aivan samal-
  327. la tavalla kuin normaaliin oletustulostuskanavaan: 
  328.  
  329. {B    cprintf( con, "Hello, %s.\n", "world" );
  330.  
  331.  
  332.  
  333.  
  334. Jos tulostat ohjelmassa vain yhteen  konsoliin,  voit  muuttaa  funktion  koodia
  335. niin, että kahva otetaan suoraan siitä: 
  336.  
  337. {B         move.l   _con(a4),d1
  338.  
  339. Tällöin sinun ei tarvitse antaa joka kerta kahvaa funktiolle, jolloin ohjelmoin-
  340. ti helpottuu, lähdekoodi lyhenee, ohjelma lyhenee ja sen suoritus nopeutuu. Huo-
  341. maa, että kun poistat yhden argumentin,  seuraavat  ovat  pinossa  neljää  tavua
  342. aiemmin, eli muuta 16 ja 20 seuraavilla riveillä 12:ksi ja 16:ksi.
  343.  
  344. Edelleen, jos tulostat vain konsoli-ikkunaasi etkä ollenkaan oletustulostuskana-
  345. vaan, voit muuttaa konekielirutiinin nimen _printf():ksi. Tämä voi kuitenkin ol-
  346. la hieman vaarallista ja sotkea koodiasi tutkailevia ihmisiä tai sinua  itseäsi,
  347. joten tee niin varoen. Pidä myös mielessäsi, että tämän jälkeen et  voi  käyttää
  348. oikeaa printf()-funktiota ja että tämä ei ole varmaankaan kovin "oikeaa"  ohjel-
  349. mointia.
  350.  
  351. Se voi kuitenkin helpottaa ohjelmointia, jos voi käyttää tavalliseen tapaan nor-
  352. maalinnäköistä printf()-funktiota ja unohtaa tyystin, että tulostus menee konso-
  353. li-ikkunaan ja printf() kutsuukin ihan erilaista funktiota kuin tavallisesti. Se
  354. on vain yksi asia vähemmän ohjelmoijan mielessä, jossa  niitä  yleensä  on  niin
  355. paljon, että helpotus on tarpeenkin.
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363. {DOhjelman suorittaminen
  364.  
  365. DOSissa on tehokkaat funktiot lapsiprosessien käynnistämiseen, mutta  niihin  ei
  366. ole syytä puuttua nyt. Yksinkertainen ja toimiva tapa  ajaa  ohjelmia  on  kyllä
  367. mielenkiintoinen. System()-funktiota kutsumalla voimme suorittaa komentoja aivan
  368. kuin ne olisi kirjoitettu shellissä. Käyttäminen on helppoa,  kunhan  toimitamme
  369. funktiolle pienen taulukon: 
  370.  
  371. {BULONG SysTags[] = {
  372. {B    NP_Priority,0,
  373. {B    TAG_DONE
  374. {B};
  375.  
  376. {B    System( "Dir", SysTags );
  377.  
  378. Tämä koodi suorittaa Dir-komennon, jonka tuloste menee ohjelman  oletustulostus-
  379. kanavalle eli normaalisti shell-ikkunaan, josta se on käynnistetty. SysTags-tau-
  380. lukkoon voidaan laittaa määrityksiä, jotka ohjaavat komennon  suoritusta,  mutta
  381. niihin ei ole tarvetta koskea. Voit  katsoa  niitä  dos/dostags.h  -tiedostosta.
  382. Toimintoa voidaan vieläkin yksinkertaistaa määrittelemällä makro: 
  383.  
  384. {B#define dos(cmd) System(cmd,SysTags)
  385.  
  386. Nyt komennon ajaminen on vieläkin helpompaa:
  387.  
  388. {B    dos("Copy DF0:Data/Blah RAM:Use");
  389.  
  390. Tuloksena on tiedoston kopioituminen ohjelman suorituksen aikana aivan kuin oli-
  391. si kirjoittanut komennon shellissä. 
  392.  
  393.  
  394. {DMuita DOS-funktioita
  395.  
  396. DOSissa on paljon funktioita myös yleisiin tarkoituksiin.  Eräs  niistä  on  De-
  397. lay(), joka panee prosessin odotustilaan annetuksi ajaksi. Sille annetaan  argu-
  398. menttina TICKien lukumäärä, jonka prosessi on nukuksissa. TICKejä on normaalisti
  399. 50 sekunnissa, joten esimerkiksi viiden sekunnin tauon ohjelman suoritukseen saa
  400. laittamalla koodiin kutsun "Delay( 250 );". Delay() on  erittäin  yksinkertainen
  401. tapa pieneen odotteluun.
  402.  
  403. Käsittelemättä vielä jäävät kokonaan hakemistot.  Palaamme  kurssin  seuraavassa
  404. tai jossakin myöhemmässä osassa DOSiin hakemistojen  käsittelyn  merkeissä  sekä
  405. teemme syvempää luotausta DOSin ympyröihin. Nyt tältä erää näkemiin ja hyvää oh-
  406. jelmoinnillista loppukevättä.
  407.